/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://www.zhiqim.com/gitcan/zhiqim/zhiqim_kernel.htm
 *
 * This file is part of [zhiqim_kernel].
 * 
 * [zhiqim_kernel] is free software: you can redistribute
 * it and/or modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * [zhiqim_kernel] is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with [zhiqim_kernel].
 * If not, see <http://www.gnu.org/licenses/>.
 */
package com.jse.util;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.CRL;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collection;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;

/**
 * SSL相关工具类
 *
 * @version v1.0.0 @author zouzhigang 2014-2-27 新建与整理
 */
public class SSL
{
    /** 缺省的信任管理器 */
    public static class DefaultTrustManager implements X509TrustManager
    {
        public X509Certificate[] getAcceptedIssuers()
        {
            return null;
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
        {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
        {
        }
    }

    /** 缺省的主机验证类 */
    public static class DefaultHostnameVerifier implements HostnameVerifier
    {
        public boolean verify(String hostname, SSLSession session) 
        {
            return true;
        }
    }
    
    /**
     * 推断密码长度SSL
     * 
     * @param cipherSuite 原值
     * @return 长度
     */
    public static int deduceKeyLength(String cipherSuite)
    {
        // 定义最常见和最不常见的
        if (cipherSuite == null)
            return 0;
        else if (cipherSuite.indexOf("WITH_RC4_128_") >= 0)
            return 128;
        else if (cipherSuite.indexOf("WITH_AES_128_") >= 0)
            return 128;
        else if (cipherSuite.indexOf("WITH_RC4_40_") >= 0)
            return 40;
        else if (cipherSuite.indexOf("WITH_3DES_EDE_CBC_") >= 0)
            return 168;
        else if (cipherSuite.indexOf("WITH_IDEA_CBC_") >= 0)
            return 128;
        else if (cipherSuite.indexOf("WITH_RC2_CBC_40_") >= 0)
            return 40;
        else if (cipherSuite.indexOf("WITH_DES40_CBC_") >= 0)
            return 40;
        else if (cipherSuite.indexOf("WITH_DES_CBC_") >= 0)
            return 56;
        else
            return 0;
    }

    /**
     * 通过SSLSession获取X509证书链
     * 
     * @param sslSession    SSL会话
     * @return              X509证书链
     */
    public static X509Certificate[] getCertChain(SSLSession sslSession)
    {
        try
        {
            javax.security.cert.X509Certificate javaxCerts[] = sslSession.getPeerCertificateChain();
            if (javaxCerts == null || javaxCerts.length == 0)
                return null;

            int length = javaxCerts.length;
            X509Certificate[] javaCerts = new X509Certificate[length];

            java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509");
            for (int i = 0; i < length; i++)
            {
                byte bytes[] = javaxCerts[i].getEncoded();
                ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
                javaCerts[i] = (X509Certificate) cf.generateCertificate(stream);
            }

            return javaCerts;
        }
        catch (SSLPeerUnverifiedException pue)
        {
            return null;
        }
        catch (Exception e)
        {
            return null;
        }
    }

    /**
     * 获取KeyStore，指定存储路径、类型、提供者和密码
     * 
     * @param storePath     存储路径
     * @param storeType     存储类型
     * @param storeProvider 提供者
     * @param storePassword 密码
     * @return              KeyStore
     * @throws Exception    捕捉异常
     */
    public static KeyStore getKeyStore(String storePath, String storeType, String storeProvider, String storePassword)throws Exception
    {
        try (InputStream is = new FileInputStream(storePath);)
        {
            return getKeyStore(is, storeType, storeProvider, storePassword);
        }
    }
    
    /**
     * 获取KeyStore，指定流，存储类型、提供者和密码
     * 
     * @param is            
     * @param storeType     存储类型
     * @param storeProvider 提供者
     * @param storePassword 密码
     * @return              KeyStore
     * @throws Exception    捕捉异常
     */
    public static KeyStore getKeyStore(InputStream is, String storeType, String storeProvider, String storePassword)
        throws Exception
    {
        KeyStore keystore = null;
        if (storeProvider != null)
            keystore = KeyStore.getInstance(storeType, storeProvider);
        else
            keystore = KeyStore.getInstance(storeType);

        keystore.load(is, storePassword == null ? null : storePassword.toCharArray());
        return keystore;

    }

    /**
     * 加载CRL，指定CRL路径
     * 
     * @param crlPath       CRL路径
     * @return              得到CRL列表
     * @throws Exception    捕捉异常
     */
    public static Collection<? extends CRL> loadCRL(String crlPath) throws Exception
    {
        if (crlPath == null)
            return null;
        
        try (InputStream is = new FileInputStream(crlPath))
        {
            return CertificateFactory.getInstance("X.509").generateCRLs(is);
        }
    }
}
